import set from 'lodash/set';
import get from 'lodash/get';
import cloneDeep from 'lodash/cloneDeep';
import isPlainObject from 'lodash/isPlainObject';
import { find } from 'react-sortable-tree';
import { RULES, STRING_TYPE, ARRAY_TYPE, OBJECT_TYPE } from './settings';
import { mapNodes, hasChildren, getUniqueID } from '@/utils/utils';
import isEqual from 'lodash/isEqual';
/**
 *
 * @param {object[]} rules 如：[{type: '',message: ''}]
 * @param {*} ruleType
 * @param {boolean} flag 表示`添加` or `删除`
 * @returns
 */
export function updateNodeRules(node, ruleType, flag) {
  let result = [];

  const rules = get(node, 'rules');

  // 添加（防止重复）
  if (flag) {
    if (Array.isArray(rules)) {
      const isExited = result.some(k => k.type === ruleType);
      if (!isExited) {
        result.push(RULES[ruleType]);
      }
    } else {
      result = [RULES[ruleType]];
    }
  } else if (Array.isArray(rules)) {
    // 删除

    result = result.filter(k => k.type !== ruleType);
  }

  return result;
}

/**
 * 扩展lodash 的get()方法（path=''时返回当前树）
 * @param {object} tree
 * @param {string} path 路径，如'a.b[0].c'
 * @returns
 */
export function getValue(tree, path) {
  if (!isPlainObject(tree) || typeof path !== 'string') {
    throw new Error(' `getValue()` arguments is error!');
  }

  if (path === '') {
    return tree;
  }
  return get(tree, path);
}

/**
 * 扩展lodash 的set()方法。（path=''时整棵树换掉）
 * @param {object} tree
 * @param {string} path  如：'a[0].b.c'
 * @param {*} newValue  当前path指向的属性的新的值
 * @returns
 */
export function setValue(tree, path, newValue) {
  if (!isPlainObject(tree) || typeof path !== 'string') {
    throw new Error(' `setValue()` arguments is error!');
  }

  if (path === '') {
    return newValue;
  }

  const newTree = set(cloneDeep(tree), path, newValue);

  if (isPlainObject(newTree)) {
    return newTree;
  }

  throw new Error('update tree error!');
}

export function getAttrPath(tree, func, path = []) {
  if (!Array.isArray(tree)) return [];

  for (let i = 0; i < tree.length; i++) {
    // 这里按照你的需求来存放最后返回的内容吧
    path.push(i);

    if (func(tree[i])) {
      path.shift();
      const result = path.map(k => `children[${k}]`).join('.');

      if (typeof result !== 'string') {
        return '';
      }
      return result;
    }

    if (tree[i].children) {
      const findChildren = getAttrPath(tree[i].children, func, path);

      if (findChildren.length) {
        return findChildren;
      }
    }

    path.pop();
  }

  return [];
}

export function serialize(tree, hasPath = true) {
  return mapNodes(tree, (node, parents, parent) => {
    const n = { ...node };
    if (typeof node.id !== 'string') {
      n.id = getUniqueID('_id');
    }

    if (!isPlainObject(node.state)) {
      n.state = {
        expanded: true,
      };
    }

    if (hasPath) {
      return n;
    }

    if (!parent) {
      n.nodePath = [];
    } else {
      n.nodePath = [...parent.nodePath, parent.nodeType === ARRAY_TYPE ? '*' : n.nodeName];
    }

    return n;
  });
}

export function getNodeById(tree, id) {
  let result;

  function walk(arr) {
    for (let i = 0; i < arr.length; i++) {
      if (arr[i].id === id) {
        result = arr[i];
        break;
      }

      if (hasChildren(arr[i])) {
        walk(arr[i].children);
      }
    }
  }

  walk(tree);
  return result;
}

// 从groups中过滤出属于当前分支的（prefix=[1,0] indexes=[1,0,0] 就是当前分支）
export function getCurrentGroups(node) {
  const { groups = [], prefix = [] } = node;

  return groups.filter(k => {
    if (!Array.isArray(get(k, 'indexes'))) {
      return false;
    }

    const p = k.indexes.slice(0, -1);

    return isEqual(p, prefix);
  });
}

// 从node.groups中提取当前groupIndex的副本，没找到返回undefined
export function getCurrentGroup(node) {
  const { groupIndex } = node;
  const groups = getCurrentGroups(node);

  return groups[groupIndex];
}

// group 是数组且非空
export function hasGroups(node) {
  const r = get(node, 'groups');
  return r && Array.isArray(r) && r.length >= 1;
}

// 当前副本是否已经配置过rules
export function hasRules(node) {
  const group = getCurrentGroup(node);
  const rules = get(group, 'rules');

  return isPlainObject(group) && Array.isArray(rules) && rules.length > 0;
}
